#ifndef _sdl_resource_h_
#define _sdl_resource_h_

#include "sdl_debug.h"
#include "sdl_options.h"
#include "sdl_prim.h"
#include "sdl_singleton.h"
#include <iosfwd>
#include <fstream>
#include <list>
#include "boost/program_options.hpp"
#include "boost/filesystem.hpp"
#include "boost/algorithm/string.hpp"



#ifndef	sdl_primary_search_path
#define sdl_primary_search_path "."
#endif


namespace fs = boost::filesystem;

struct sdl_resource {

    typedef enum {
        path, stream, rwops, undef
    } mode_t;
    friend std::ostream & operator<<(std::ostream & o, sdl_resource & r);
private:
    mode_t mode;
    std::string name;
    fs::path _path;
    std::ios * _stream;
    SDL_RWops * _rwops;
public:

    sdl_resource(const std::string & n = "null") :
    name(n),
    _stream(NULL),
    _rwops(NULL),
    mode(undef) {
    }

    operator bool () const {
        return mode != undef;
    }

    operator std::string() const {
        return name;
    }

    bool operator!() const {
        return mode == undef;
    }

    bool operator==(const mode_t & m) const {
        return mode == m;
    }

    bool operator!=(const mode_t & m) const {
        return mode != m;
    }

    bool is_path() const {
        return mode == path;
    }

    bool is_stream() const {
        return mode == stream;
    }

    bool is_rwops() const {
        return mode == rwops;
    }

    bool valid() const {
        return mode != undef;
    }

    static sdl_resource from_path(const fs::path & p, const std::string & _name = "generic resource") {
        sdl_resource ret(p.string());
        ret.name = _name;
        ret.mode = path;
        ret._path = p;
        return ret;
    }

    fs::path get_path() const {
        if (mode != path)
            throw sdlex::bad_resource(name);
        else
            return _path;
    }

    std::string get_path_str() const {
        if (mode != path)
            throw sdlex::bad_resource(name);
        else
            return _path.string();
    }

    std::string get_name() const {
        return name;
    }

    std::ios * get_stream() const {
        if (mode != stream)
            throw sdlex::bad_resource(name);
        else
            return _stream;
    }

    SDL_RWops * get_rwops() const {
        if (mode != rwops)
            throw sdlex::bad_resource(name);
        else
            return _rwops;
    }
};

extern std::ostream & operator<<(std::ostream & o, sdl_resource & r);

class sdl_resource_loader : public sdl_prim, public sdl_singleton<sdl_resource_loader>,
depends<sdl_options>,
depends<sdl_debug::debug> {
    ///ścieżki przeszukiwania
    std::vector<fs::path> search_dirs;
    ///do użycia w przyszłości
    std::vector<fs::path> search_zips;
public:

    sdl_resource_loader(const std::string & path = sdl_primary_search_path) :
    sdl_prim("resource loader") {
        add_search_dir(fs::path(path));
        if (give<sdl_options > ()->is_set("media.directories")) {
            std::vector<std::string> vals = give<sdl_options > ()->get<std::vector<std::string> >("media.directories");
            for (int i = 0; i < vals.size(); i++)
                add_search_dir(vals[i]);
        }
    }

    sdl_resource load(const std::string & res_name) {
        for (int i = 0; i < search_dirs.size(); i++)
            if (fs::exists(search_dirs[i] / res_name)) {
                _msg("resource", 3, "znaleziono " << search_dirs[i] / res_name);
                return sdl_resource::from_path(search_dirs[i] / res_name);
            }
        _msg("resource", 20, "nie znaleziono zasobu " << res_name << ", spróbuj dodać ścieżkę do zasobu w pliku konfiguracyjnym albo na linii poleceń");
        return sdl_resource();
    }

    void add_search_dir(const fs::path & val) {
        if (fs::exists(val) && fs::is_directory(val)) {
            // wkładamy ścieżkę na listę
            search_dirs.push_back(val);
            _msg("resource", 6, "dodano katalog: " << val);
            // szukamy zipów, które będziemy przeglądać w tym katalogu
            for (fs::directory_iterator i(val); i != fs::directory_iterator(); i++) {
                if (boost::to_lower_copy(fs::extension(i->path())) == std::string(".zip")) {
                    search_zips.push_back(i->path());
                    _msg("resource", 6, "dodano archiwum: " << i->path());
                }
            }
        } else {
            _msg("resource", 40, "nie znaleziono katalogu lub błędny katalog: " << val);
        }
    }
    //TODO: ładowanie z zipów
    //
};




#endif //_sdl_resource_h_

